package com.naiterui.ehp.bs.patient.service.function.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.naiterui.common.redis.RedisUtil;
import com.naiterui.ehp.bp.bo.patient.ConvertWxImageBO;
import com.naiterui.ehp.bp.domain.Department;
import com.naiterui.ehp.bp.domain.Doctor;
import com.naiterui.ehp.bp.domain.DoctorCharge;
import com.naiterui.ehp.bp.domain.DrChargeConfig;
import com.naiterui.ehp.bp.domain.Patient;
import com.naiterui.ehp.bp.domain.PatientPersonDoctor;
import com.naiterui.ehp.bp.domain.PatientPersonDoctorPK;
import com.naiterui.ehp.bp.support.context.ResourceHolder;
import com.naiterui.ehp.bp.support.exception.BusinessException;
import com.naiterui.ehp.bp.utils.date.DateUtil;
import com.naiterui.ehp.bp.utils.lang.ConfigUtil;
import com.naiterui.ehp.bs.patient.constants.CacheConstant;
import com.naiterui.ehp.bs.patient.dao.IDoctorDao;
import com.naiterui.ehp.bs.patient.dao.IPatientDao;
import com.naiterui.ehp.bs.patient.dao.IPatientPersonDoctorDao;
import com.naiterui.ehp.bs.patient.exception.ExceptionCodes;
import com.naiterui.ehp.bs.patient.repository.IApDepartmentRepository;
import com.naiterui.ehp.bs.patient.service.IDoctorChargeService;
import com.naiterui.ehp.bs.patient.service.IPatientDoctorService;
import com.naiterui.ehp.bs.patient.service.function.IFunctionService;
import com.naiterui.ehp.bs.patient.utils.NoticeUtil;
import com.naiterui.ehp.bs.patient.utils.cache.BaseParamCacheUtil;
import com.naiterui.ehp.bs.patient.utils.cache.PatientCacheUtil;
import com.naiterui.ehp.bs.patient.utils.constants.PatientConstant;
import com.naiterui.ehp.bs.patient.utils.exception.PatientBusinessException;
import com.naiterui.ehp.bs.patient.vo.doctor.DoctorVO;
import com.naiterui.ehp.bs.patient.vo.parameters.DepartmentVO;
import com.naiterui.ehp.bs.patient.vo.patient.PatientVO;
import com.naiterui.ehp.bs.patient.vo.patient.PersonalRelation;
import com.naiterui.ehp.bs.wechat.service.IMediaApiService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author gaoliangliang
 * @date 2019/11/27 8:21 下午
 * @since 1.0.0
 */
@Slf4j
@Service
@AllArgsConstructor
public class ApFunctionServiceImpl implements IFunctionService {
    private final IPatientDao patientDao;
    private final IDoctorDao doctorDao;
    private final IMediaApiService mediaApiService;
    private final IPatientPersonDoctorDao patientPersonDoctorDao;
    private final IDoctorChargeService doctorChargeService;
    private final IApDepartmentRepository departmentRepository;
    @Override
    public void isdDleteDoctorPatientRelation(Long doctorId, Long patientId) throws BusinessException {
        PatientPersonDoctor patientPersonDoctor = getPatientPersonDoctor(doctorId, patientId);
        if (patientPersonDoctor.getRelationFlag() == PatientPersonDoctor.RELATION_FLAG_DELETE) {
            log.debug("医患关系已经删除 doctorId:{} patientId:{}", doctorId, patientId);
            throw new BusinessException(ExceptionCodes.DOCTOR_PATIENT_RELATION_DELETE);
        }
    }


    /**
     * 通过医生id患者id获取医患关系
     */
    private PatientPersonDoctor getPatientPersonDoctor(Long doctorId, Long patientId) throws BusinessException {
        PatientPersonDoctorPK personPK = new PatientPersonDoctorPK();
        personPK.setDoctorId(doctorId);
        personPK.setPatientId(patientId);
        PatientPersonDoctor patientPersonDoctor = patientPersonDoctorDao.findByPatientIdAndDoctorId(patientId, doctorId);
        if (patientPersonDoctor == null) {
            try {
                log.info("首次咨询医生，建立关联关系，doctorId {}, patientId {}", doctorId, patientId);
                // 建立医患绑定关系
                addPersonalDoctor(doctorId, patientId, 0, PatientConstant.PERSONAL_SOURCE_WEIXIN);

            } catch (Exception e) {
                log.error("专家名医首次建立关联关系异常，doctorId {}, patientId {}", doctorId, patientId, e);
                throw new BusinessException(ExceptionCodes.FAILED);
            }
            patientPersonDoctor = patientPersonDoctorDao.findByPatientIdAndDoctorId(patientId, doctorId);
//            log.error("没有医患关系 doctorId:{} patientId:{}", doctorId, patientId);
//            throw new BusinessException(ExceptionCodes.PATIENT_DOCTOR_RELATION_ERROR);
        }
        return patientPersonDoctor;
    }

    @Override
    public void isAllDoctorsDisable(Long patientId) throws PatientBusinessException {
        log.debug("判断患者的医生是否全部禁用 patientId:{}", patientId);
        List<PatientPersonDoctor> personPatientBindDoctor = patientPersonDoctorDao.getPersonPatientBindDoctor(patientId);
        // 如果没有私人医生，那么就是没有全禁用
        if (personPatientBindDoctor.isEmpty()) {
            log.debug("患者没有私人医生 patientId:{}", patientId);
            return;
        }
        List<Long> doctorIds = personPatientBindDoctor.stream().map(patientPersonDoctor -> patientPersonDoctor.getPersonPK().getDoctorId())
                                                      .collect(Collectors.toList());
        List<Doctor> doctors = doctorDao.getDoctorByIds(doctorIds);

        if (doctors.isEmpty()) {
            log.debug("患者私人医生全部禁用 patientId:{}", patientId);
            throw new PatientBusinessException(ExceptionCodes.DOCTOR_ACCOUNT_DISABLE);
        }

    }

    @Override
    public List<ConvertWxImageBO> convertImage(List<ConvertWxImageBO> convertWxImageList) {
        if (CollectionUtil.isEmpty(convertWxImageList)) {
            return convertWxImageList;
        }

        String dayTime = DateUtil.getCurrentCustomizeFormatDate(DateUtil.DAY_TIME_FORMAT);

        return convertWxImageList.stream().peek(convertImage -> {
            Long sn = RedisUtil.keyOps().incr(CacheConstant.PATIENT_DISEASE_IMG_SN + dayTime);
            String filePath = "/patient/" + dayTime + "/" + sn + ".jpg";
            convertImage.setImageUrl(filePath);
        }).collect(Collectors.toList());
    }

    @Override
    @Async
    public void syncImageFile(List<ConvertWxImageBO> imageList) {
        if (CollectionUtil.isEmpty(imageList)) {
            return;
        }
        imageList.forEach(imageBO -> {
            try {
                byte[] mediaFile = mediaApiService.downloadTempMedia(imageBO.getMediaId());
                String fileDir = ConfigUtil.getString("emr.file.path");
                File file = new File(fileDir + imageBO.getImageUrl());
                FileUtils.forceMkdirParent(file);
                FileUtils.writeByteArrayToFile(file, mediaFile);
            } catch (IOException e) {
                log.error("convertImage ERROR ; mediaId={},fileUrl={},error={}", imageBO.getMediaId(), imageBO.getImageUrl(), e.getMessage());
            }
        });
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PersonalRelation addPersonalDoctor(Long doctorId, Long patientId, Integer firstRecom, int soucre) throws Exception {
        Patient patient = patientDao.get(patientId);
        Doctor doctor = doctorDao.get(doctorId);
        PersonalRelation personalRelation = addPersonalDoctor(patient, doctor, soucre);
        // 设置首推医生
        if (firstRecom == 1) {
            patient.setRecomDoctor(doctorId);
            // 注册来源为推荐
            patient.setRegistSource(PatientConstant.REGIST_SOURCE_RECOM);
            patientDao.saveOrUpdatePatient(patient);
        }
        return personalRelation;

    }
    /**
     * <绑定医生></p>
     * 设置医生和患者的私人医生关系
     *
     * @param patient 患者实体
     * @param doctor  医生实体
     *
     * @return
     *
     * @throws BusinessException PersonalRelation <返回值描述>
     * @Throws 异常信息
     * @History 2015年11月5日 下午11:16:24 by Amber
     */
    private PersonalRelation addPersonalDoctor(Patient patient, Doctor doctor, int source) throws BusinessException {

        // 患者信息校验
        // 患者不存在
        if (patient == null || patient.getId() == null) {
            log.error("addPersonalDoctor Error ; patient not exist : patientId {}, doctorId {}", null, doctor == null ? null : doctor.getId());
            throw new PatientBusinessException(ExceptionCodes.PATIENT_NOT_EXIST);
        }
        // 患者账号被禁用
        if (patient.getAccountStatus() != 0) {
            log.error("addPersonalDoctor Error ; patient account status wrong : patientId {}, doctorId{}", patient.getId(),
                    doctor == null ? null : doctor.getId());
            throw new PatientBusinessException(ExceptionCodes.PATIENT_ACCOUNT_ERROR);
        }

        // 医生信息校验
        if (doctor == null || doctor.getId() == null) {
            log.error("addPersonalDoctor Error ; doctor not exist : patientId {}, doctorId {}", patient.getId(), null);
            throw new PatientBusinessException(ExceptionCodes.DOCTOR_NOT_EXIST);
        }
        // 医生账号被禁用
        if (doctor.getAccountStatus() != 0) {
            log.error("addPersonalDoctor Error ; doctor account status wrong : patientId {}, doctorId {}", patient.getId(), doctor.getId());
            throw new PatientBusinessException(ExceptionCodes.DOCTOR_ACCOUNT_ERROR);
        }

        Long patientId = patient.getId();
        Long doctorId = doctor.getId();

        PatientPersonDoctor patientPersonDoctor = patientPersonDoctorDao.findByPatientIdAndDoctorId(patientId, doctorId);
        if (patientPersonDoctor != null) {
            if (patientPersonDoctor.getRelationFlag() == PatientPersonDoctor.RELATION_FLAG_DELETE) {
                log.debug("医患关系已经删除 doctorId:{} patientId:{}", doctorId, patientId);
                throw new BusinessException(ExceptionCodes.DOCTOR_PATIENT_RELATION_DELETE);
            } else {
                //使用ResourceHolder回传患者id
                log.info("资源持有器线程上下文-存入数据-医患绑定异常，patientId {}", patient.getId());
                ResourceHolder.bindResource("patientId", patient.getId());
                // 已经绑定，无需再绑定
                log.error("addPersonalDoctor Error ; have bound : patientId {}, doctorId {}", patient.getId(), doctor.getId());
                throw new PatientBusinessException(ExceptionCodes.HAVE_BOUND);
            }
        }

        // 绑定私人医生关系
        patientDao.addPersonalDoctor(doctorId, patientId, source);

        // 解除关注关系
        if (patientDao.existAttendRelation(patientId, doctor.getId())) {
            deleteAttend(patientId, doctor.getId());
        }

        // 获取患者的个人医生信息
        PersonalRelation personalRelation = findPersonalDoctor(doctor, patient);

        // 更新患者最新绑定医生缓存
        DoctorVO newPersonal = buildNewPersonalDoctor(doctor);

        newPersonal.setBindTime(System.currentTimeMillis());
        PatientCacheUtil.addPatientNewPersonalDoctorToRedis(patientId, newPersonal);

        // 优先级低，避免影响原有妥投回调逻辑 by mudou
        /*try {
            this.scaleService.saveMouthTest(doctorId, patientId, patient.getOpenId());
            this.scaleService.publishEdu(doctor, patientId);
        } catch (Exception e) {
            LOGGER.error("[患者扫码量表信息存储]saveScaleRemind ERROR ", e);
        }*/
        //绑定私人医生后，设置医生图文咨询费
        //this.remoter.addDoctorDefaultMessageCharge(patientId, doctorId);
        // 异步处理通知
        NoticeUtil.newPatientNotice(doctorId, patientId);
        return personalRelation;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public DoctorVO deleteAttend(Long patientId, Long doctorId) throws BusinessException {
        Patient patient = patientDao.get(patientId);
        // 患者不存在
        if (patient == null) {
            log.error("deleteAttend Error ; patient not exist : patientId {}, doctorId {}", patientId, doctorId);
            throw new PatientBusinessException(ExceptionCodes.PATIENT_NOT_EXIST);
        }
        // 患者账号被禁用
        if (patient.getAccountStatus() != 0) {
            log.error("deleteAttend Error ; patient account status wrong : patientId {}, doctorId {}", patientId, doctorId);
            throw new PatientBusinessException(ExceptionCodes.PATIENT_ACCOUNT_ERROR);
        }
        // 不存在关注关系，不需要解除关注
        if (!patientDao.existAttendRelation(patientId, doctorId)) {
            log.error("deleteAttend Error ; no attention : patientId {}, doctorId {}", patientId, doctorId);
            throw new PatientBusinessException(ExceptionCodes.HAVE_NO_ATTENTION);
        }

        // 删除关联关系
        patientDao.cancelAttend(patientId, doctorId);
        DoctorVO doctorVo = new DoctorVO();
        doctorVo.setRelation(PatientConstant.RELATIONN_TYPE_NULL);
        return doctorVo;
    }
    private PersonalRelation findPersonalDoctor(Doctor doctor, Patient patient) {
        // 处理返回，医生信息
        DoctorVO doctorVo = new DoctorVO();
        doctorVo.setDoctorId(doctor.getId());
        doctorVo.setName(doctor.getName() == null ? "" : doctor.getName());
        doctorVo.setPhotoOnState(doctor.getHeadUrl(), doctor.getStatus());
        doctorVo.setAuthStatus(doctor.getStatus());
        // 图文咨询收费设置
        DoctorCharge doctorCharge = doctorChargeService.getDoctorChargeInfo(doctor.getId(), DrChargeConfig.TYPE_MESSAGE);
        // 如果开启图文咨询
        if (doctorCharge != null) {
            doctorVo.setConsultCost(doctorCharge.getCharge());
        }

        // 处理返回，患者信息
        PatientVO patientVo = new PatientVO();
        patientVo.setPatientId(patient.getId());
        // 患者完善过资料时返回真是姓名
        patientVo.setNickName(StringUtils.isNotEmpty(patient.getName()) ? patient.getName()
                : (StringUtils.isEmpty(patient.getNickName()) ? "互联网医院患者" : patient.getNickName()));
        patientVo.setCanTalk(patient.cantalk());

        // 处理返回，关联信息
        PersonalRelation personalRelation = new PersonalRelation();
        personalRelation.setDoctor(doctorVo);
        personalRelation.setPatient(patientVo);

        // 本时间与实际关联时间可能有误差，不影响页面显示
        personalRelation.setCreateAt(new Date());
        return personalRelation;
    }
    /**
     * 构建最新私人医生信息 PatientDoctorService.buildNewPersonalDoctor()<BR> <P>Author :
     * Amber </P> <P>Date : 2015年9月11日 </P>
     *
     * @param doctor
     *
     * @return
     */
    private DoctorVO buildNewPersonalDoctor(Doctor doctor) {
        DoctorVO newPersonal = new DoctorVO();
        newPersonal.setDoctorId(doctor.getId());
        newPersonal.setName(doctor.getName());
        // 缓存获取医生科室信息
        // 未认证医生无科室等数据处理,医生手动输入科室departmentId为0
        if (null != doctor.getDepartmentId() && 0 != doctor.getDepartmentId()) {// 存在科室，且非自定义
            DepartmentVO departmentVO = BaseParamCacheUtil.getDepartmentFromRedis(doctor.getDepartmentId());
            newPersonal.setDepartmentId(doctor.getDepartmentId());
            if (departmentVO != null) {// 获取科室名
                newPersonal.setDepartment(departmentVO.getName());
            } else {// 缓存没有科室信息，数据库读取
                Department department = departmentRepository.get(doctor.getDepartmentId());
                newPersonal.setDepartment(department.getName());
            }
        } else {
            newPersonal.setDepartmentId(0);
            newPersonal.setDepartment(doctor.getCustomDepartment() == null ? "" : doctor.getCustomDepartment());
        }
        // 获取医生医院信息
        if (null != doctor.getHospitalId()) {
            String hpName = doctorDao.getHospitalName(doctor.getHospitalId());
            newPersonal.setHospitalId(doctor.getHospitalId());
            if (StringUtils.isEmpty(hpName)) {
                newPersonal.setHospital(doctor.getHospitalName());
            } else {
                newPersonal.setHospital(hpName);
                newPersonal.setHospital(hpName);
            }
        } else {
            newPersonal.setHospitalId(0);
            newPersonal.setHospital("");
        }
        return newPersonal;
    }
}
